/**
 * 区块链服务
 */

import Web3 from 'web3'
import { API_BASE_URL, WEB3_RPC_URL, NETWORK_ID, DEFAULT_GAS_PRICE, DEFAULT_GAS_LIMIT, CONTRACT_NAMES } from '../api/config'
import type { Contract } from 'web3-eth-contract'

/**
 * 合约地址接口
 */
export interface ContractAddresses {
  registry: string
  governance: string
  nft: string
}

/**
 * 区块链服务类
 */
class BlockchainService {
  private web3: Web3 | null = null
  private contracts: {
    registry?: Contract
    governance?: Contract
    nft?: Contract
  } = {}
  private contractAddresses: ContractAddresses | null = null
  private currentAccount: string | null = null

  /**
   * 初始化 Web3
   */
  async init(): Promise<void> {
    try {
      // 检查是否有 MetaMask 等钱包插件
      if (typeof window !== 'undefined' && (window as any).ethereum) {
        this.web3 = new Web3((window as any).ethereum)
        console.log('✅ Web3 已通过 MetaMask 初始化')
      } else {
        // 使用 HTTP Provider
        this.web3 = new Web3(new Web3.providers.HttpProvider(WEB3_RPC_URL))
        console.log('✅ Web3 已通过 HTTP Provider 初始化')
      }

      // 验证网络
      await this.checkNetwork()
    } catch (error) {
      console.error('❌ Web3 初始化失败:', error)
      throw error
    }
  }

  /**
   * 检查网络
   */
  async checkNetwork(): Promise<void> {
    if (!this.web3) throw new Error('Web3 未初始化')

    const networkId = await this.web3.eth.net.getId()
    const networkIdStr = String(networkId)
    console.log('🌐 当前网络 ID:', networkIdStr)

    if (networkIdStr !== NETWORK_ID) {
      console.warn(`⚠️ 网络 ID 不匹配，期望 ${NETWORK_ID}，实际 ${networkIdStr}`)
    }
  }

  /**
   * 连接钱包
   */
  async connectWallet(): Promise<string> {
    if (!this.web3) await this.init()

    try {
      if ((window as any).ethereum) {
        // 请求用户授权
        const accounts = await (window as any).ethereum.request({
          method: 'eth_requestAccounts',
        })
        this.currentAccount = accounts[0]
        console.log('✅ 钱包已连接:', this.currentAccount)
        return this.currentAccount
      } else {
        throw new Error('请安装 MetaMask 钱包')
      }
    } catch (error) {
      console.error('❌ 钱包连接失败:', error)
      throw error
    }
  }

  /**
   * 获取当前账户
   */
  async getCurrentAccount(): Promise<string | null> {
    if (!this.web3) await this.init()

    try {
      const accounts = await this.web3!.eth.getAccounts()
      this.currentAccount = accounts[0] || null
      return this.currentAccount
    } catch (error) {
      console.error('❌ 获取账户失败:', error)
      return null
    }
  }

  /**
   * 从后端获取合约地址
   */
  async fetchContractAddresses(): Promise<ContractAddresses> {
    try {
      const response = await fetch(`${API_BASE_URL}/blockchain/contracts/addresses`)
      const result = await response.json()
      
      console.log('📥 收到合约地址响应:', result)
      
      // 后端返回格式可能是: { code: 200, data: {...} } 或直接 {...}
      let addresses
      
      if (result.code === 200 && result.data) {
        addresses = result.data
      } else if (result.registry && result.governance && result.nft) {
        addresses = result
      } else {
        throw new Error('Invalid contract addresses format')
      }
      
      // 验证地址格式
      if (!addresses.registry || !addresses.governance || !addresses.nft) {
        throw new Error('Missing contract addresses')
      }
      
      this.contractAddresses = {
        registry: addresses.registry,
        governance: addresses.governance,
        nft: addresses.nft,
      }
      
      console.log('✅ 合约地址获取成功:', this.contractAddresses)
      return this.contractAddresses!
    } catch (error) {
      console.error('❌ 获取合约地址失败:', error)
      throw error
    }
  }

  /**
   * 从后端获取合约 ABI
   */
  async fetchContractABI(contractName: string): Promise<any> {
    try {
      const response = await fetch(`${API_BASE_URL}/blockchain/contract/${contractName}/abi`)
      const result = await response.json()
      
      console.log(`📥 收到 ${contractName} ABI 响应:`, { 
        code: result.code, 
        hasData: !!result.data,
        dataType: typeof result.data 
      })
      
      // 后端返回格式: { code: 200, message: "success", data: "[...]" }
      let abi
      
      if (result.code === 200 && result.data) {
        // data 字段可能是字符串或数组
        if (typeof result.data === 'string') {
          // 如果是字符串，需要 JSON.parse
          try {
            abi = JSON.parse(result.data)
          } catch (parseError) {
            console.error('❌ 解析 ABI 字符串失败:', parseError)
            throw new Error(`Failed to parse ABI string: ${parseError}`)
          }
        } else if (Array.isArray(result.data)) {
          abi = result.data
        } else {
          throw new Error(`Unexpected data type: ${typeof result.data}`)
        }
      } else {
        throw new Error(`API returned error: ${result.message || 'Unknown error'}`)
      }
      
      if (!Array.isArray(abi)) {
        throw new Error(`Invalid ABI format: expected array, got ${typeof abi}`)
      }
      
      console.log(`✅ ${contractName} ABI 获取成功 (${abi.length} 个接口定义)`)
      return abi
    } catch (error) {
      console.error(`❌ 获取 ${contractName} ABI 失败:`, error)
      throw error
    }
  }

  /**
   * 初始化合约
   */
  async initContracts(addresses?: ContractAddresses): Promise<void> {
    if (!this.web3) await this.init()

    try {
      // 如果没有提供地址，从后端获取
      if (!addresses) {
        addresses = await this.fetchContractAddresses()
      }

      // 获取 ABI（使用可配置的合约名称）
      const registryABI = await this.fetchContractABI(CONTRACT_NAMES.REGISTRY)
      const governanceABI = await this.fetchContractABI(CONTRACT_NAMES.GOVERNANCE)
      const nftABI = await this.fetchContractABI(CONTRACT_NAMES.NFT)

      // 创建合约实例
      console.log('🔨 创建 Registry 合约实例:', {
        abi: `${registryABI.length} 个接口`,
        address: addresses.registry,
        contractName: CONTRACT_NAMES.REGISTRY
      })
      
      // 验证 ABI 中是否有 createFamily 方法
      const hasCreateFamily = registryABI.some((item: any) => item.name === 'createFamily' && item.type === 'function')
      console.log(`   ${hasCreateFamily ? '✅' : '❌'} createFamily 方法${hasCreateFamily ? '存在' : '不存在'}`)
      
      if (!hasCreateFamily) {
        console.error('⚠️ ABI 中缺少 createFamily 方法！')
        console.log('   可用方法:', registryABI.filter((i: any) => i.type === 'function').map((i: any) => i.name).slice(0, 10))
      }
      
      this.contracts.registry = new this.web3!.eth.Contract(registryABI, addresses.registry)
      
      console.log('🔍 Registry 合约方法:', Object.keys(this.contracts.registry.methods || {}).slice(0, 10))
      
      console.log('🔨 创建 Governance 合约实例:', {
        abi: `${governanceABI.length} 个接口`,
        address: addresses.governance
      })
      this.contracts.governance = new this.web3!.eth.Contract(governanceABI, addresses.governance)
      
      console.log('🔨 创建 NFT 合约实例:', {
        abi: `${nftABI.length} 个接口`,
        address: addresses.nft
      })
      this.contracts.nft = new this.web3!.eth.Contract(nftABI, addresses.nft)

      console.log('✅ 合约初始化完成')
      console.log('🔍 Registry 合约方法:', Object.keys(this.contracts.registry.methods || {}).slice(0, 10))
    } catch (error) {
      console.error('❌ 合约初始化失败:', error)
      throw error
    }
  }

  /**
   * 获取 Registry 合约
   */
  getRegistryContract(): Contract {
    if (!this.contracts.registry) {
      throw new Error('Registry 合约未初始化')
    }
    return this.contracts.registry
  }

  /**
   * 获取 Governance 合约
   */
  getGovernanceContract(): Contract {
    if (!this.contracts.governance) {
      throw new Error('Governance 合约未初始化')
    }
    return this.contracts.governance
  }

  /**
   * 获取 NFT 合约
   */
  getNFTContract(): Contract {
    if (!this.contracts.nft) {
      throw new Error('NFT 合约未初始化')
    }
    return this.contracts.nft
  }

  /**
   * 获取账户余额
   */
  async getBalance(address: string): Promise<string> {
    if (!this.web3) await this.init()
    const balance = await this.web3!.eth.getBalance(address)
    return this.web3!.utils.fromWei(balance, 'ether')
  }

  /**
   * 获取交易收据
   */
  async getTransactionReceipt(txHash: string): Promise<any> {
    if (!this.web3) await this.init()
    return await this.web3!.eth.getTransactionReceipt(txHash)
  }

  /**
   * 等待交易确认
   */
  async waitForTransaction(txHash: string, confirmations = 1): Promise<any> {
    if (!this.web3) await this.init()

    console.log('⏳ 等待交易确认:', txHash)

    return new Promise((resolve, reject) => {
      let confirmedBlocks = 0
      const checkInterval = setInterval(async () => {
        try {
          const receipt = await this.web3!.eth.getTransactionReceipt(txHash)
          
          if (receipt) {
            confirmedBlocks++
            console.log(`⏳ 确认中... (${confirmedBlocks}/${confirmations})`)

            if (confirmedBlocks >= confirmations) {
              clearInterval(checkInterval)
              console.log('✅ 交易已确认:', receipt)
              resolve(receipt)
            }
          }
        } catch (error) {
          clearInterval(checkInterval)
          reject(error)
        }
      }, 3000)

      // 超时处理（30秒）
      setTimeout(() => {
        clearInterval(checkInterval)
        reject(new Error('交易确认超时'))
      }, 30000)
    })
  }

  /**
   * 发送交易
   */
  async sendTransaction(tx: any): Promise<string> {
    if (!this.web3) await this.init()
    if (!this.currentAccount) {
      await this.connectWallet()
    }

    const txParams = {
      from: this.currentAccount,
      gasPrice: DEFAULT_GAS_PRICE,
      gas: DEFAULT_GAS_LIMIT,
      ...tx,
    }

    console.log('🚀 发送交易:', txParams)
    const receipt = await this.web3!.eth.sendTransaction(txParams)
    console.log('✅ 交易已发送:', receipt.transactionHash)
    return receipt.transactionHash
  }

  /**
   * 估算 Gas
   */
  async estimateGas(tx: any): Promise<number> {
    if (!this.web3) await this.init()
    return await this.web3!.eth.estimateGas(tx)
  }

  /**
   * 获取当前 Gas Price
   */
  async getGasPrice(): Promise<string> {
    if (!this.web3) await this.init()
    return await this.web3!.eth.getGasPrice()
  }

  /**
   * 获取当前区块高度
   */
  async getBlockNumber(): Promise<number> {
    if (!this.web3) await this.init()
    return await this.web3!.eth.getBlockNumber()
  }

  /**
   * 监听合约事件
   */
  listenToEvent(
    contractType: 'registry' | 'governance' | 'nft',
    eventName: string,
    callback: (event: any) => void,
  ): void {
    const contract = this.contracts[contractType]
    if (!contract) {
      throw new Error(`${contractType} 合约未初始化`)
    }

    contract.events[eventName]()
      .on('data', (event: any) => {
        console.log('📡 收到事件:', eventName, event)
        callback(event)
      })
      .on('error', (error: any) => {
        console.error('❌ 事件监听错误:', error)
      })
  }

  /**
   * 获取 Web3 实例
   */
  getWeb3(): Web3 {
    if (!this.web3) {
      throw new Error('Web3 未初始化')
    }
    return this.web3
  }
}

// 导出单例
export const blockchainService = new BlockchainService()

export default blockchainService

